<?php
  namespace mytp;

  // 使用追根溯源命名空间 -- 可以通过反射API找到所属一切
  use ReflectionClass; 
  use ReflectionMethod;

  // 容器, 用来创建对象实例放在容器中
  // 当创建的对象已经存在时,不创建,返回该对象  
  class Container {
    // 存放实例的数组
    protected $instances = [];
    protected static $instance;

    public function make($className){
      // 判断对象是否存在
      if(!isset($this->instances[$className])){
        // 通过想创建实例的类名创建反射对象
        $reflect = new ReflectionClass($className);
        // 获取构造方法
        $constructor = $reflect->getConstructor();
        // 创建构造方法依赖的对象, 将对象保存在 $args 中
        $args = $constructor ? $this->bindParam($constructor) : [];
        // $this->instances[$className] = new $className();
        // 实例化类, 并传入 $args 参数 
        $this->instances[$className] = $reflect->newInstanceArgs($args);
      }
      return $this->instances[$className];
    }

    public function bindParam(ReflectionMethod$reflect){
      $args = [];
      // 获取构造函数的参数
      $params = $reflect->getParameters();
      foreach($params as $param){
        // 获取参数的类名
        $className = $param->getType();
        // echo $className->getName(). "<br>";
        if($className){
          $args[] = $this->make($className->getName());
        }
      }
      return $args;
    }

    // Container也得是同一个
    public static function getInstance(){
      if(!isset(static::$instance)){
        static::$instance = new static();
      }
      return static::$instance;
    }
  }
?>